using System;
using System.Net;
using System.Net.Sockets;
using Org.Mentalis.Network.ProxySocket;
using ProxyServer.Pool;

namespace ProxyServer.ProxyImpl
{
    public delegate void DestroyDelegate(Client client);

    public abstract class Client : IDisposable
    {
        private ILogger logger = Logger.GetLogger();

        private readonly DestroyDelegate destroyer;

        protected Client(Socket clientSocket, DestroyDelegate destroyer)
        {
            ClientSocket = clientSocket;
            this.destroyer = destroyer;
            Buffer = BufferContext.GetBuffManager().GetBuffer();
        }

        public Socket ClientSocket { get; private set; }

        public ProxySocket DestinationSocket { get; set; }

        public BuffUnit Buffer { get; private set; }

        public bool IsDisposed { get; set; }

        #region IDisposable Members

        public void Dispose()
        {
            if (IsDisposed) return;
            IsDisposed = true;

            try
            {
                ClientSocket.Shutdown(SocketShutdown.Both);
                ClientSocket.Close();
            }
            catch (Exception e)
            {
                logger.Error(e.Message);
            }

            try
            {
                if (DestinationSocket != null)
                {
                    DestinationSocket.Shutdown(SocketShutdown.Both);
                    DestinationSocket.Close();
                }
            }
            catch (Exception e)
            {
                logger.Error(e.Message);
            }

            BufferContext.GetBuffManager().FreeBuffer(Buffer);

            if (destroyer != null)
                destroyer(this);
        }

        #endregion

        public override string ToString()
        {
            try
            {
                return "Incoming connection from " + ((IPEndPoint)ClientSocket.RemoteEndPoint).Address;
            }
            catch
            {
                return "Client connection";
            }
        }

        public abstract void StartHandshake();
    }
}